@node Higher-level synchronization
@section Higher-level synchronization

This section details the various higher-level thread synchronization
devices that Scheme48 provides.

@subsection Condition variables

@stindex condvars
@dfn{Condition variables} are multiple-assignment cells on which
readers block.  Threads may wait on condition variables; when some
other thread assigns a condition variable, all threads waiting on it
are revived.  The @code{condvars} structure exports all of these
condition-variable-related names.

In many concurrency systems, condition variables are operated in
conjunction with mutual exclusion locks.  On the other hand, in
Scheme48, they are used in conjunction with its optimistic concurrency
devices.

@deffn procedure make-condvar [id] @returns{} condvar
@deffnx procedure condvar? object @returns{} boolean
Condition variable constructor & disjoint type predicate.  @var{Id} is
used purely for debugging.
@end deffn

@deffn procedure maybe-commit-and-wait-for-condvar condvar @returns{} boolean
@deffnx procedure maybe-commit-and-set-condvar! condvar value @returns{} boolean
@code{Maybe-commit-and-wait-for-condvar} attempts to commit the current
proposal.  If the commit succeeded, the current thread is blocked on
@var{condvar}, and when the current thread is woken up,
@code{maybe-commit-and-wait-for-condvar} returns @code{#t}.  If the
commit did not succeed, @code{maybe-commit-and-wait-for-condvar}
immediately returns @code{#f}.  @code{Maybe-commit-and-set-condvar!}
attempts to commit the current proposal as well.  If it succeeds, it is
noted that @var{condvar} has a value, @var{condvar}'s value is set to
be @var{value}, and all threads waiting on @var{condvar} are woken up.

@strong{Note:} Do not use these in atomic transactions as delimited by
@code{call-ensuring-atomicity} @etc{}; see the note in @ref{Optimistic
concurrency} on this matter for details.
@end deffn

@deffn procedure condvar-has-value? condvar @returns{} boolean
@deffnx procedure condvar-value condvar @returns{} value
@code{Condvar-has-value?} tells whether or not @var{condvar} has been
assigned.  If it has been assigned, @code{condvar-value} accesses the
value to which it was assigned.
@end deffn

@deffn procedure set-condvar-has-value?! condvar boolean @returns{} unspecified
@deffnx procedure set-condvar-value! condvar value @returns{} unspecified
@code{Set-condvar-has-value?!} is used to tell whether or not
@var{condvar} is assigned.  @code{Set-condvar-value!} sets
@var{condvar}'s value.

@strong{Note:} @code{Set-condvar-has-value?!} should be used only with
a second argument of @code{#f}.  @code{Set-condvar-value!} is a very
dangerous routine, and @code{maybe-commit-and-set-condvar!} is what one
should almost always use, except if one wishes to clean up after
unassigning a condition variable.
@end deffn

@subsection Placeholders

@stindex placeholders
@dfn{Placeholders} are similar to condition variables, except that they
may be assigned only once; they are in general a much simpler mechanism
for throw-away temporary synchronization devices.  They are provided by
the @code{placeholders} structure.

@deffn procedure make-placeholder [id] @returns{} placeholder
@deffnx procedure placeholder? object @returns{} boolean
Placeholder constructor & disjoint type predicate.  @var{Id} is used
only for debugging purposes when printing placeholders.
@end deffn

@deffn procedure placeholder-value placeholder @returns{} value
@deffnx procedure placeholder-set! placeholder value @returns{} unspecified
@code{Placeholder-value} blocks until @var{placeholder} is assigned, at
which point it returns the value assigned.  @code{Placeholder-set!}
assigns @var{placeholder}'s value to @var{value}, awakening all threads
waiting for @var{placeholder}.  It is an error to assign a placeholder
with @code{placeholder-set!} that has already been assigned.
@end deffn

@subsection Value pipes

@cindex thread communication channels, asynchronous
@cindex asynchronous thread communication channels
@dfn{Value pipes} are asynchronous communication pipes between threads.
The @code{value-pipes} structure exports these value pipe operations.

@deffn procedure make-pipe [size [id]] @returns{} value-pipe
@deffnx procedure pipe? object @returns{} boolean
@code{Make-pipe} is the value pipe constructor.  @var{Size} is a limit
on the number of elements the pipe can hold at one time.  @var{Id} is
used for debugging purposes only in printing pipes.  @code{Pipe?} is
the disjoint type predicate for value pipes.
@end deffn

@deffn procedure empty-pipe? pipe @returns{} boolean
@deffnx procedure empty-pipe! pipe @returns{} unspecified
@code{Empty-pipe?} returns @code{#t} if @var{pipe} has no elements in
it and @code{#f} if not.  @code{Empty-pipe!} removes all elements from
@code{pipe}.
@end deffn

@deffn procedure pipe-read! pipe @returns{} value
@deffnx procedure pipe-maybe-read! pipe @returns{} value or @code{#f}
@deffnx procedure pipe-maybe-read?! pipe @returns{} [boolean value]
@code{Pipe-read!} reads a value from @var{pipe}, removing it from the
queue.  It blocks if there are no elements available in the queue.
@code{Pipe-maybe-read!} attempts to read & return a single value from
@var{pipe}; if no elements are available in its queue, it instead
returns @code{#f}.  @code{Pipe-maybe-read?!} does similarly, but it
returns two values: a boolean, signifying whether or not a value was
read; and the value, or @code{#f} if no value was read.
@code{Pipe-maybe-read?!} is useful when @var{pipe} may contain the
value @code{#f}.
@end deffn

@deffn procedure pipe-write! pipe value @returns{} unspecified
@deffnx procedure pipe-push! pipe value @returns{} unspecified
@deffnx procedure pipe-maybe-write! pipe value @returns{} boolean
@code{Pipe-write!} attempts to add @var{value} to @var{pipe}'s queue.
If @var{pipe}'s maximum size, as passed to @code{make-pipe} when
constructing the pipe, is either @code{#f} or greater than the number
of elements in @var{pipe}'s queue, @code{pipe-write!} will not block;
otherwise it will block until a space has been made available in the
pipe's queue by another thread reading from it.  @code{Pipe-push!} does
similarly, but, in the case where the pipe is full, it pushes the first
element to be read out of the pipe.  @code{Pipe-maybe-write!} is also
similar to @code{pipe-write!}, but it returns @code{#t} if the pipe was
not full, and it @emph{immediately} returns @code{#f} if the pipe was
full.
@end deffn
